package com.dabai.iot.core.service.impl;

import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.dabai.common.core.exception.ServiceException;
import com.dabai.common.core.utils.Func;
import com.dabai.common.core.utils.StringUtils;
import com.dabai.common.tdengine.core.TDEngineTemplate;
import com.dabai.common.tdengine.model.TDField;
import com.dabai.iot.common.enums.FunctionType;
import com.dabai.iot.core.convert.ThingModelItemConvert;
import com.dabai.iot.core.dto.ThingModelItemInput;
import com.dabai.iot.core.dto.ThingModelItemQuery;
import com.dabai.iot.core.dto.ThingModelItemUpdate;
import com.dabai.iot.core.entity.ThingModelBlockEntity;
import com.dabai.iot.core.entity.ThingModelItemEntity;
import com.dabai.iot.core.mapper.ThingModelItemMapper;
import com.dabai.iot.core.service.IProductService;
import com.dabai.iot.core.service.IThingModelBlockService;
import com.dabai.iot.core.service.IThingModelItemService;
import com.dabai.iot.core.tsl.TslPropDataType;
import com.dabai.iot.core.tsl.specs.TslBoolSpec;
import com.dabai.iot.core.tsl.specs.TslFloatSpec;
import com.dabai.iot.core.tsl.specs.TslIntSpec;
import com.dabai.iot.core.tsl.specs.TslTextSpec;
import com.dabai.iot.core.utils.IotTDField;
import com.dabai.iot.core.utils.IotTDSql;
import com.dabai.iot.core.vo.ThingModelItemVO;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;

/**
 * 物模型属性 Service 实现类
 *
 * @author kev1n
 */
@Service
@RequiredArgsConstructor
public class ThingModelItemServiceImpl extends ServiceImpl<ThingModelItemMapper, ThingModelItemEntity> implements IThingModelItemService {

    private final IProductService productService;
    private final IThingModelBlockService thingModelBlockService;
    private final TDEngineTemplate tdEngineTemplate;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean addThingModelItem(ThingModelItemInput input) {
        ThingModelItemEntity entity = ThingModelItemConvert.INSTANCE.convert(input);

        // 参数校验
        validateParams(entity);

        // 获得物模型功能模块
        ThingModelBlockEntity modelBlock = thingModelBlockService.getById(input.getBlockId());
        if (modelBlock == null) {
            // 物模型功能模块不存在
            throw new ServiceException("物模型功能模块不存在");
        }

        entity.setProductId(modelBlock.getProductId());
        entity.setProductKey(modelBlock.getProductKey());
        entity.setBlockId(modelBlock.getId());
        entity.setBlockIdentifier(modelBlock.getBlockIdentifier());
        if (entity.getSort() == null) {
            entity.setSort(1);
        }
        if (Func.isBlank(entity.getName())) {
            entity.setName(entity.getIdentifier());
        }

        // 校验属性标识符是否重复
        if (checkIdentifierDuplicate(entity)) {
            throw new ServiceException(String.format("属性标识符[%s]已存在", entity.getIdentifier()));
        }

        boolean result = this.save(entity);
        if (result) {
            result = productService.updateProductTsl(modelBlock.getProductId());
            if (!result) {
                // 更新物模型TSL失败
                throw new ServiceException("更新物模型 TSL 失败");
            }

            try {
                // 创建 TD 超级表
                saveOrUpdatePropertySTable(entity);
            } catch (Throwable e) {
                throw new ServiceException("操作失败," + e.getMessage());
            }
        }
        return result;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateThingModelItem(ThingModelItemUpdate update) {
        ThingModelItemEntity entity = getById(update.getId());
        if (entity == null) {
            return false;
        }

        entity.setName(update.getName());
        entity.setMin(update.getMin());
        entity.setMax(update.getMax());
        entity.setTextLength(update.getTextLength());
        entity.setScale(update.getScale());
        entity.setUnit(update.getUnit());
        entity.setTrueDesc(update.getTrueDesc());
        entity.setFalseDesc(update.getFalseDesc());
        entity.setMethod(update.getMethod());
        entity.setSort(update.getSort());
        if (entity.getSort() == null) {
            entity.setSort(1);
        }

        // 参数校验
        validateParams(entity);

        boolean result = this.updateById(entity);
        if (result) {
            result = productService.updateProductTsl(entity.getProductId());
            if (!result) {
                // 更新物模型TSL失败
                throw new ServiceException("更新物模型 TSL 失败");
            }
        }
        return result;
    }

    private void validateParams(ThingModelItemEntity entity) {
        if (FunctionType.property.getValue().equals(entity.getFunctionType()) ||
            FunctionType.command.getValue().equals(entity.getFunctionType())) {
            if (TslPropDataType.INT32.getType().equals(entity.getDataType())) {

            } else if (TslPropDataType.FLOAT.getType().equals(entity.getDataType())) {

            } else if (TslPropDataType.BOOL.getType().equals(entity.getDataType())) {
                if (StringUtils.isAnyBlank(entity.getTrueDesc(), entity.getFalseDesc())) {
                    // 布尔值不能为空
                    throw new ServiceException("布尔值不能为空");
                }
                if (entity.getTrueDesc().equals(entity.getFalseDesc())) {
                    // 布尔值不能相同
                    throw new ServiceException("布尔值不能相同");
                }

            } else if (TslPropDataType.TEXT.getType().equals(entity.getDataType())) {
                if (entity.getTextLength() == null) {
                    // 数据长度不能为空
                    throw new ServiceException("数据长度不能为空");
                }
                if (entity.getTextLength() < 1 || entity.getTextLength() > 10240) {
                    // 字符串长度应为1-10240
                    throw new ServiceException("字符串长度应为1-10240");
                }
            }
        }
    }

    /**
     * 校验属性标识符是否重复
     */
    boolean checkIdentifierDuplicate(ThingModelItemEntity entity) {
        return this.lambdaQuery()
            .eq(ThingModelItemEntity::getBlockId, entity.getBlockId())
            .eq(ThingModelItemEntity::getIdentifier, entity.getIdentifier())
            .ne(ObjectUtil.isNotNull(entity.getId()), ThingModelItemEntity::getId, entity.getId())
            .exists();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean removeThingModelItem(Long id) {
        ThingModelItemEntity thingModelItem = getById(id);
        if (thingModelItem == null) {
            return false;
        }

        boolean result = removeById(id);
        if (result) {
            result = productService.updateProductTsl(thingModelItem.getProductId());
            if (!result) {
                // 更新物模型TSL失败
                throw new ServiceException("更新物模型 TSL 失败");
            }

            Long blockId = thingModelItem.getBlockId();
            Long count = this.lambdaQuery().eq(ThingModelItemEntity::getBlockId, blockId).count();
            if (count > 0) {
                //
                dropSTableColumn(thingModelItem);
            } else {
                // drop
                dropSTable(thingModelItem);
            }
        }
        return result;
    }

    @Override
    public IPage<ThingModelItemVO> getThingModelItemPage(IPage<ThingModelItemEntity> page, ThingModelItemQuery modelItemQuery) {
        QueryWrapper<ThingModelItemEntity> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda()
            .eq(Func.isNotEmpty(modelItemQuery.getBlockId()), ThingModelItemEntity::getBlockId, modelItemQuery.getBlockId())
            .like(Func.isNotEmpty(modelItemQuery.getName()), ThingModelItemEntity::getName, modelItemQuery.getName())
            .eq(Func.isNotEmpty(modelItemQuery.getFunctionType()), ThingModelItemEntity::getFunctionType, modelItemQuery.getFunctionType())
            .eq(Func.isNotEmpty(modelItemQuery.getDataType()), ThingModelItemEntity::getDataType, modelItemQuery.getDataType())
            .orderByDesc(ThingModelItemEntity::getSort)
            .orderByAsc(ThingModelItemEntity::getCreateTime);

        IPage<ThingModelItemEntity> result = page(page, queryWrapper);
        return result.convert(item -> {
            ThingModelItemVO vo = ThingModelItemConvert.INSTANCE.convertDetail(item);
            if (FunctionType.property.getValue().equals(item.getFunctionType()) ||
                FunctionType.command.getValue().equals(item.getFunctionType())) {

                if (TslPropDataType.INT32.getType().equals(item.getDataType())) {
                    TslIntSpec spec = new TslIntSpec();
                    spec.setMin(item.getMin());
                    spec.setMax(item.getMax());
                    spec.setUnit(item.getUnit());

                    vo.setDataSpecs(spec);
                } else if (TslPropDataType.FLOAT.getType().equals(item.getDataType())) {
                    TslFloatSpec spec = new TslFloatSpec();
                    spec.setMin(item.getMin());
                    spec.setMax(item.getMax());
                    spec.setScale(item.getScale());
                    spec.setUnit(item.getUnit());

                    vo.setDataSpecs(spec);
                } else if (TslPropDataType.BOOL.getType().equals(item.getDataType())) {
                    TslBoolSpec spec = new TslBoolSpec();
                    spec.setTrueDesc(item.getTrueDesc());
                    spec.setFalseDesc(item.getFalseDesc());

                    vo.setDataSpecs(spec);
                } else if (TslPropDataType.TEXT.getType().equals(item.getDataType())) {
                    TslTextSpec spec = new TslTextSpec();
                    spec.setTextLength(item.getTextLength());

                    vo.setDataSpecs(spec);
                }
            }
            return vo;
        });
    }

    @Override
    public List<ThingModelItemEntity> getItemListByBlockId(Long blockId) {
        return this.lambdaQuery().eq(ThingModelItemEntity::getBlockId, blockId).list();
    }


    //    @Override
//    public IPage<ThingModelItemEntity> getThingModelItemPage1(IPage<ThingModelItemEntity> page, ThingModelItemQuery modelItemQuery) {
//        QueryWrapper<ThingModelItemEntity> queryWrapper = new QueryWrapper<>();
//        queryWrapper.lambda()
//                .eq(Func.isNotEmpty(modelItemQuery.getBlockId()), ThingModelItemEntity::getBlockId, modelItemQuery.getBlockId())
//                .like(Func.isNotEmpty(modelItemQuery.getName()), ThingModelItemEntity::getName, modelItemQuery.getName())
//                .eq(Func.isNotEmpty(modelItemQuery.getItemType()), ThingModelItemEntity::getItemType, modelItemQuery.getItemType())
//                .eq(Func.isNotEmpty(modelItemQuery.getDataType()), ThingModelItemEntity::getDataType, modelItemQuery.getDataType())

    /// /                .eq(ThingModelItemEntity::getIsDeleted, 0)
//                .orderByDesc(ThingModelItemEntity::getSort)
//                .orderByAsc(ThingModelItemEntity::getCreateTime);
//
//        return page(page, queryWrapper);
//    }


//    @Override
//    public List<ThingModelItemVO> getItemListByProductAndItemType(Long productId, Integer itemType) {
//        List<ThingModelBlockEntity> thingModelList = thingModelBlockService.lambdaQuery()
//            .eq(ThingModelBlockEntity::getProductId, productId)
//            .list();
//
//        List<ThingModelItemVO> list = new ArrayList<>();
//        for (ThingModelBlockEntity thingModel : thingModelList) {
//            List<ThingModelItemEntity> itemList = this.lambdaQuery()
//                .eq(ThingModelItemEntity::getBlockId, thingModel.getId())
//                .eq(ThingModelItemEntity::getFunctionType, itemType)
//                .orderByDesc(ThingModelItemEntity::getSort)
//                .list();
//            if (Func.isNotEmpty(itemList)) {
//
//                for (ThingModelItemEntity item : itemList) {
//                    ThingModelItemVO detail = ThingModelItemConvert.INSTANCE.convertDetail(item);
//                    detail.setModelName(thingModel.getBlockName());
//                    resolveThingModelDataSpec(detail, item);
//
//                    list.add(detail);
//                }
//            }
//        }
//        return list;
//    }

//    @Override
//    public boolean checkDefaultModelPropertyExist(Long productId) {
//        ProductEntity product = productService.getById(productId);
//        if (product == null) {
//            return false;
//        }
//        ThingModelBlockEntity thingModel = thingModelBlockService.lambdaQuery()
//            .eq(ThingModelBlockEntity::getProductId, productId)
//            .eq(ThingModelBlockEntity::getBlockIdentifier, "DEFAULT")
//            .one();
//        if (thingModel == null) {
//            return false;
//        }
//        Long modelId = thingModel.getId();
//        List<ThingModelItemEntity> list = this.lambdaQuery()
//            .eq(ThingModelItemEntity::getBlockId, modelId)
//            .list();
//        return Func.isNotEmpty(list);
//    }

//    private ThingModelItemVO resolveThingModelDataSpec(ThingModelItemVO detail, ThingModelItemEntity item) {
//        if (TslPropDataType.INT32.getType().equals(detail.getDataType())) {
//            TslIntSpec spec = new TslIntSpec();
//            spec.setMin(item.getMin());
//            spec.setMax(item.getMax());
//            spec.setUnit(item.getUnit());
//
//            detail.setDataSpecs(spec);
//        } else if (TslPropDataType.FLOAT.getType().equals(detail.getDataType())) {
//            TslFloatSpec spec = new TslFloatSpec();
//            spec.setMin(item.getMin());
//            spec.setMax(item.getMax());
//            spec.setScale(item.getScale());
//            spec.setUnit(item.getUnit());
//
//            detail.setDataSpecs(spec);
//        } else if (TslPropDataType.BOOL.getType().equals(detail.getDataType())) {
//            TslBoolSpec spec = new TslBoolSpec();
//            String[] boolArray = item.getBoolDesc().split(",");
//            spec.setTrueDesc(boolArray[0]);
//            spec.setFalseDesc(boolArray[1]);
//
//            detail.setDataSpecs(spec);
//        } else if (TslPropDataType.TEXT.getType().equals(detail.getDataType())) {
//            TslTextSpec spec = new TslTextSpec();
//            spec.setMaxLength(item.getMaxLength());
//
//            detail.setDataSpecs(spec);
//        }
//
//        return detail;
//    }

    private void saveOrUpdatePropertySTable(ThingModelItemEntity item) {
        String sTableName = IotTDSql.getDevicePropertyStbName(item.getProductKey(), item.getBlockIdentifier());

        List<TDField> tableInfo = tdEngineTemplate.getTableInfo(sTableName);
        // 表不存在才会为空，其它会报异常跳出
        if (tableInfo == null || tableInfo.isEmpty()) {
            tableInfo = new ArrayList<>();
            // 时间字段必须在最开始的位置
            tableInfo.add(new TDField("ts", "timestamp", -1));
            // 添加属性字段
            tableInfo.add(IotTDField.form(item));

            List<TDField> tagList = Collections.singletonList(
                new TDField("device_sn", "NCHAR", 64)
            );

            // 创建超级表
            tdEngineTemplate.createSTable(sTableName, tableInfo, tagList);
            return;
        }

        // 转换成 map，方便处理
        Map<String, TDField> fieldMap = new HashMap<>();
        for (TDField tdField : tableInfo) {
            fieldMap.put(tdField.getField(), tdField);
        }

        // 判断是否需要新增字段
        if (fieldMap.get(item.getIdentifier()) == null) {
            List<TDField> addFields = List.of(IotTDField.form(item));
            tdEngineTemplate.addSTableColumn(sTableName, addFields);
        }
    }

    private void modifySTableColumn(ThingModelItemEntity item) {
        String sTableName = IotTDSql.getDevicePropertyStbName(item.getProductKey(), item.getBlockIdentifier());

        List<TDField> tableInfo = tdEngineTemplate.getTableInfo(sTableName);
        // 表不存在才会为空，其它会报异常跳出
        if (tableInfo == null || tableInfo.isEmpty()) {
            return;
        }

        List<TDField> modifyFields = List.of(IotTDField.form(item));
        tdEngineTemplate.modifySTableColumn(sTableName, modifyFields);
    }

    private void dropSTable(ThingModelItemEntity item) {
        String sTableName = IotTDSql.getDevicePropertyStbName(item.getProductKey(), item.getBlockIdentifier());

        List<TDField> tableInfo = tdEngineTemplate.getTableInfo(sTableName);
        // 表不存在才会为空，其它会报异常跳出
        if (tableInfo == null || tableInfo.isEmpty()) {
            return;
        }

        tdEngineTemplate.dropSTable(sTableName);
    }

    private void dropSTableColumn(ThingModelItemEntity item) {
        String sTableName = IotTDSql.getDevicePropertyStbName(item.getProductKey(), item.getBlockIdentifier());

        List<TDField> tableInfo = tdEngineTemplate.getTableInfo(sTableName);
        // 表不存在才会为空，其它会报异常跳出
        if (tableInfo == null || tableInfo.isEmpty()) {
            return;
        }

        // 转换成 map，方便处理
        Map<String, TDField> fieldMap = new HashMap<>();
        for (TDField tdField : tableInfo) {
            fieldMap.put(tdField.getField(), tdField);
        }

        // 判断是否需要删除字段
        if (fieldMap.get(item.getIdentifier()) != null) {
            List<String> dropFields = List.of(item.getIdentifier());
            tdEngineTemplate.dropSTableColumn(sTableName, dropFields);
        }
    }

}
